﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PessMvc.Models;
using PessModel;
using System.Data;
using PessMvc.Helpers;
using System.Web.Security;
using System.Data.Entity.Validation;
using System.Diagnostics;
using DynamicQueryLib;
using LinqKit;

namespace PessMvc.Lib
{
    public class ArchiveBL:IArchiveBL
    {
        private PESSEntities db;
        private ModelStateDictionary _errorLog;
        public ArchiveBL(ModelStateDictionary modelState)
        {
            db = new PESSEntities();
            _errorLog = modelState;
        }
        public void AddFeedback(FeedbackModel feedback,int subjectID)
        {
            if (this.IfFeedbackEmpty(feedback.ArchiveSerialNumber))
            {
                var archive = db.Archives.Where(a => a.SerialNumber == feedback.ArchiveSerialNumber).FirstOrDefault();
                var subject=db.Subjects.Find(subjectID);
                if (archive == null)
                {
                    _errorLog.AddModelError("档案不存在", "档案不存在，请确认档案号。");
                }
                else if (archive.SubjectID != subjectID)
                {
                    _errorLog.AddModelError("档案非本学科组", string.Format("档案({0})不属于学科({1})", archive.SerialNumber, subject.Name));
                }
                else
                {
                    archive.ProjectSN = feedback.ProjectSN;
                    archive.ReviewFeedback = feedback.ReviewFeedback;
                    archive.Conclusion = feedback.Conclusion;
                    db.Entry(archive).State =System.Data.Entity.EntityState.Modified;
                    db.SaveChanges();
                }
            }
            else
            {
                _errorLog.AddModelError("反馈意见已经存在", string.Format("档案({0})的反馈意见已经存在，不可覆盖。",feedback.ArchiveSerialNumber));
            }

        }

        private bool IfFeedbackEmpty(string archiveSerialNumber)
        {
            bool ifNoFeedback = true;
            var archive = db.Archives.Where(a => a.SerialNumber.Trim() == archiveSerialNumber.Trim()).FirstOrDefault();
            if (archive != null 
                && ((archive.ReviewFeedback!=null&& archive.ReviewFeedback.Trim() != "")
                || (archive.Conclusion!=null&&archive.Conclusion.Trim() != "")
                || (archive.ProjectSN!=null&&archive.ProjectSN.Trim() != "")))
            {
                ifNoFeedback = false;
            }
            return ifNoFeedback;
        }

        public IEnumerable<FeedbackModel> GetFeedbacks(int subjectID)
        {
            var feedbacks=from a in db.Archives.Where(a => a.SubjectID == subjectID)
                          select new FeedbackModel() { ArchiveSerialNumber = a.SerialNumber, Conclusion = a.Conclusion, ReviewFeedback = a.ReviewFeedback, ProjectSN = a.ProjectSN };
            return feedbacks;
        }

        public FeedbackModel ArchiveFeedback(string serialNumber)
        {
            FeedbackModel model=null;
            var archive= db.Archives.Where(a => a.SerialNumber == serialNumber).FirstOrDefault();
            if (archive != null)
            {
                model = new FeedbackModel() { ArchiveSerialNumber = serialNumber, Conclusion = archive.Conclusion, ProjectSN = archive.ProjectSN, ReviewFeedback = archive.ReviewFeedback };
            }
            else
            {
                _errorLog.AddModelError("档案不存在", string.Format("档案({0})不存在。", serialNumber));
            }
            return model;
        }

        public bool UpdateFeedback(FeedbackModel model)
        {
            bool updateSuccess=false;
            var archive = db.Archives.Where(a => a.SerialNumber == model.ArchiveSerialNumber).FirstOrDefault();
            if (archive != null)
            {
                archive.ProjectSN = model.ProjectSN;
                archive.Conclusion = model.Conclusion;
                archive.ReviewFeedback = model.ReviewFeedback;
                db.Entry(archive).State =System.Data.Entity.EntityState.Modified;
                db.SaveChanges();

                updateSuccess=true;
            }
            else
            {
                _errorLog.AddModelError("档案不存在", string.Format("档案({0})不存在。", model.ArchiveSerialNumber));
                updateSuccess=false;
            }
            return updateSuccess;
        }

        public bool AddDisplayNames(int activityID)
        {
            //If such an activity exists!
            if(db.Activities.Where(a=>a.ID==activityID).Count()<=0)
            {
                _errorLog.AddModelError("活动不存在",string.Format("ID{0}的活动不存在！",activityID));
                return false;
            }
            //If not all DisplayNames haven been added to database.
            List<System.Reflection.PropertyInfo> properties = Utility.GetProperties<Archive>();  //Properties that shall be added to database.
            var names = from n in db.ArchiveDisplayNames  //Properties have been added to database
                        where n.ActivityID == activityID
                        select n;
            var leftOverProperties = from p in properties
                                     where !names.Any(n => n.PropertyName == p.Name)
                                     select p;
            foreach (var p in leftOverProperties)
            {
                db.ArchiveDisplayNames.Add(new ArchiveDisplayName() { ActivityID = activityID, PropertyName = p.Name, DisplayName = Utility.Translate<PessResources.Archive>(p.Name), Visibility = 1 });
            }
            db.SaveChanges();
            //if(names.Count()>0)
            //{
            //    _errorLog.AddModelError("不能重复创建","该活动的档案属性显示名称数据已存在，不能重复创建");
            //}
            //else
            //{
            //    List<System.Reflection.PropertyInfo> properties = Utility.GetProperties<Archive>();
            //    foreach (var p in properties)
            //    {
            //        db.ArchiveDisplayNames.Add(new ArchiveDisplayName() { ActivityID = activityID, PropertyName=p.Name, DisplayName=Utility.Translate<PessResources.Archive>(p.Name),Visibility=1 });                    
            //    }
            //    db.SaveChanges();
            //}
            return true;
        }
        public bool AddArchive(Archive archive, int activityID)
        {
            if (Roles.IsUserInRole(Membership.GetUser().UserName, "Author"))
            {
                archive.AuthorSN = Membership.GetUser().UserName;
            }
            int quotaLimit = 0;
            var quota = db.CandidateQuotas.Find(archive.SubjectID, archive.CountyCode);
            bool isRowTotalEnabled = Utility.IsQuotaRowTotalEnabled(activityID);
            if (quota == null) { quotaLimit = 0; }
            else if (isRowTotalEnabled)
            {
                Activity activity = db.Activities.Find(activityID);
                var subjectIDs = from s in activity.Subjects
                                 select s.ID;
                var quotas = from q in db.CandidateQuotas
                             where subjectIDs.Contains(q.SubjectID) && q.CountyCode == archive.CountyCode
                             select q;
                quotaLimit = (int)quotas.Sum(q => q.Quota);
            }
            else
            {
                quotaLimit = Convert.ToInt32(quota.Quota);
            }
            int uploadedArchivesRowTotal = db.Archives.Where(a => a.CountyCode == archive.CountyCode && a.Subject.ActivityID == activityID).Count();
            if (quota != null
                && (
                    isRowTotalEnabled && uploadedArchivesRowTotal < quotaLimit
                    || (!isRowTotalEnabled && db.Archives.Where(a => a.CountyCode == quota.CountyCode && a.SubjectID == quota.SubjectID).Count() < quota.Quota)
                  )
                )
            {
                //Add archive to database
                if (_errorLog.IsValid)
                {
                    //Make sure the previousSN and the current one are of the same county.
                    Archive preArchive = db.Archives.Where(a => a.SerialNumber == archive.PreviousSN).FirstOrDefault();
                    if (archive.PreviousSN == null //Archive has no previous archive.
                        || preArchive != null && preArchive.CountyCode == archive.CountyCode //Previous archive and the current one belong to the same county.
                        )
                    {
                        try
                        {
                            db.Archives.Add(archive);
                            db.SaveChanges();
                        }
                        catch (DbEntityValidationException e)
                        {
                            foreach (var eve in e.EntityValidationErrors)
                            {
                                Debug.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                                    eve.Entry.Entity.GetType().Name, eve.Entry.State);
                                foreach (var ve in eve.ValidationErrors)
                                {
                                    Debug.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
                                        ve.PropertyName, ve.ErrorMessage);
                                }
                            }
                            throw;
                        }

                        //Set archive's serialnumber. If the archive has no specified SerialNumber.
                        db.Entry(archive).Reference(e => e.Subject).Load();
                        if (archive.SerialNumber == null || archive.SerialNumber.Trim() == "")
                        {
                            archive.SerialNumber = string.Format("Y{0}A{1}S{2}V{3}",
                                archive.Subject.Activity.AdminYear.Value.Year,
                                archive.Subject.ActivityID,
                                archive.SubjectID,
                                archive.ID
                            );
                            db.Entry(archive).State = System.Data.Entity.EntityState.Modified;
                            db.SaveChanges();
                        }

                        //存放申报表
                        //this.SaveArchiveFormToFolder(activityID, archive);

                        return true;//RedirectToAction("Details", new { id = archive.ID });
                    }
                    else
                    {
                        _errorLog.AddModelError(string.Empty, "历史档案不存在，或者非本区档案！");
                    }
                }

                return false;//View(archive);
            }
            else
            {
                string errorMsg = "";
                if (quota != null)
                {
                    errorMsg = string.Format("{0}({1}区)的配额已满！", quota.Subject.Name, quota.County.Name);
                }
                else
                {
                    errorMsg = string.Format("配额不存在！");
                }
                _errorLog.AddModelError(string.Empty, errorMsg);
                return false; //View(archive);
            }
        }
        public bool IfExists(Archive archive,int activityID)
        {
            //keyword = keyword.Trim();
            //Get string type properties from Archive
            var properties = Utility.GetArchiveProperties<Archive>();
            properties = (from p in properties  //any property of DateTime should be excluded. Because operator only supports contains.
                          where p.PropertyType == typeof(string)
                          select p).ToList();
            //if (hideArchiveDetails == true)
            //{
            //    properties = properties.Where(p =>
            //        p.Name.Equals("SerialNumber") || p.Name.Equals("ProjectTitle")
            //        ).ToList();
            //}
            //Prepare the filters
            List<DynamicQueryLib.Filter> filterList = new List<DynamicQueryLib.Filter>();
            for (int i = 0; i < properties.Count; i++)// var prop in properties)
            {
                DynamicQueryLib.Filter f = new DynamicQueryLib.Filter();
                if (i == 0)
                {
                    f.Connector = FilterConnectorType.AND;//the first connector must be AND, otherwise, you get a true
                }
                else
                {
                    f.Connector = FilterConnectorType.AND;
                }
                f.PropertyName = properties[i].Name;
                f.PropertyType = typeof(string);
                if (archive.GetType().GetProperty(f.PropertyName).GetValue(archive, null) != null)
                {
                    f.Values.Add(archive.GetType().GetProperty(f.PropertyName).GetValue(archive, null).ToString());
                    f.Operator = RelationalOperators.Contains;
                    filterList.Add(f);
                }
            }
            var predicate = LambdaExpressionHelper<Archive>.CreatePredicate<Archive>(filterList);
            var activityArchives = db.Archives.AsExpandable().Where(a => a.Subject.ActivityID == activityID);
            var archives = activityArchives.Where(predicate);
            bool simillarArchivesFound = false;
            if (archives.Count()>0)
            {
                simillarArchivesFound = true;
            }
            return simillarArchivesFound;
        }
    }
}